﻿using System;
using System.Reflection;
using System.Xml.Linq;

namespace FluentlyXml.Core.Deserialization.BuiltInDeserializers
{
	internal static class DeserializationBehaviors
	{
		public static object Default(IDeserializationContext context, XElement source, PropertyInfo property)
		{
			if (typeof(IConvertible).IsAssignableFrom(property.PropertyType) ||
				property.PropertyType.IsNullableType())
			{
				return BaseTypeDeserializer(context, source, property);
			}

			return context.Deserialize(property.PropertyType, source, context);
		}

		private static object BaseTypeDeserializer(IDeserializationContext context, XElement source, PropertyInfo property)
		{
			var rawValue = source.Value;

			object destinationValue;

			//TOOD: Push this down, use the config to construct and set values.  It could default
			//		to use Convert.ChangeType, but make it overridable. 
			if (string.IsNullOrEmpty(rawValue))
			{
				destinationValue = property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null;
			}
			else if (property.PropertyType.IsNullableType())
			{
				destinationValue = Convert.ChangeType(rawValue, Nullable.GetUnderlyingType(property.PropertyType));
			}
			else if (property.PropertyType.IsEnum)
			{
				destinationValue = Enum.Parse(property.PropertyType, rawValue);
			}
			else
			{
				destinationValue = Convert.ChangeType(rawValue, property.PropertyType);
			}

			return destinationValue;
		}

		public static object Ignore(IDeserializationContext context, XElement source, PropertyInfo property)
		{
			return null;
		}
	}
}